#include "zrpc/http/http_request.h"

namespace zrpc
{
  void HttpRequest::SetMethod() { method_ = kContent; }

  bool HttpRequest::SetMethod(const char *start, const char *end)
  {
    assert(method_ == kInvalid);
    std::string m(start, end);
    if (m == "GET")
    {
      method_ = kGet;
    }
    else if (m == "POST")
    {
      method_ = kPost;
    }
    else if (m == "HEAD")
    {
      method_ = kHead;
    }
    else if (m == "PUT")
    {
      method_ = kPut;
    }
    else if (m == "DELETE")
    {
      method_ = kDelete;
    }
    else
    {
      method_ = kInvalid;
    }
    return method_ != kInvalid;
  }

  const char *HttpRequest::MethodString() const
  {
    const char *result = "UNKNOWN";
    switch (method_)
    {
    case kGet:
    {
      result = "GET";
      break;
    }
    case kPost:
    {
      result = "POST";
      break;
    }
    case kHead:
    {
      result = "HEAD";
      break;
    }
    case kPut:
    {
      result = "PUT";
      break;
    }
    case kDelete:
    {
      result = "DELETE";
      break;
    }
    default:
      break;
    }
    return result;
  }

  const std::string &HttpRequest::GetPath() const { return path_; }

  void HttpRequest::SetPath(const char *start, const char *end)
  {
    path_.assign(start, end);
  }

  void HttpRequest::SetQuery(const char *start, const char *end)
  {
    query_.assign(start, end);
  }

  void HttpRequest::SetBody(const char *start, const char *end)
  {
    body_.assign(start, end);
  }

  const std::string &HttpRequest::GetBody() const { return body_; }
  const std::string &HttpRequest::GetQuery() const { return query_; }

  void HttpRequest::SetReceiveTime(int64_t t) { receive_time_ = t; }

  void HttpRequest::AddContent(const char *start, const char *colon,
                               const char *end)
  {
    std::string field(start, colon);
    ++colon;
    while (colon < end && isspace(*colon))
    {
      ++colon;
    }

    std::string value(colon, end);
    while (!value.empty() && isspace(value[value.size() - 1]))
    {
      value.resize(value.size() - 1);
    }
    content_length_ = atoi(value.c_str());
  }

  void HttpRequest::AddHeader(const char *start, const char *colon,
                              const char *end)
  {
    std::string field(start, colon);
    ++colon;
    while (colon < end && isspace(*colon))
    {
      ++colon;
    }

    std::string value(colon, end);
    while (!value.empty() && isspace(value[value.size() - 1]))
    {
      value.resize(value.size() - 1);
    }
    headers_[field] = value;
  }

  std::string HttpRequest::GetHeader(const std::string &field) const
  {
    std::string result;
    auto it = headers_.find(field);
    if (it != headers_.end())
    {
      result = it->second;
    }
    return result;
  }

  const std::map<std::string, std::string> &HttpRequest::GetHeaders() const
  {
    return headers_;
  }

  void HttpRequest::Swap(HttpRequest &that)
  {
    std::swap(method_, that.method_);
    path_.swap(that.path_);
    query_.swap(that.query_);
    headers_.swap(that.headers_);
  }

  void HttpRequest::AddHeader(const std::string &key, const std::string &value)
  {
    headers_[key] = value;
  }

  void HttpRequest::AppendToBuffer(Buffer *output) const
  {
    if (method_ == kPost)
    {
      output->Append("POST ");
    }
    else if (method_ == kGet)
    {
      output->Append("GET ");
    }

    output->Append(query_.c_str(), query_.size());
    output->Append(" HTTP/1.1\r\n");

    for (const auto &header : headers_)
    {
      output->Append(header.first);
      output->Append(": ");
      output->Append(header.second);
      output->Append("\r\n");
    }

    output->Append("\r\n");
    if (body_.size() > 0)
    {
      output->Append(body_.c_str(), body_.size());
    }
  }
} // namespace zrpc